﻿
using MarkJcz;
using Newtonsoft.Json;
using NModbus;
using NModbus.Serial;
using OxyPlot;
using OxyPlot.Axes;
using OxyPlot.Series;
using Prism.Ioc;
using Prism.Services.Dialogs;
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using TestDemo.Models;
using MessageBox = System.Windows.Forms.MessageBox;

namespace TestDemo.ViewModels
{
    public class MainWindowViewModel : BindableBase
    {
        #region 变量
        Param param;
        private readonly IDialogService dialogService;
        CancellationTokenSource source0, source, source2, source3;
        SerialPort serialPort = new SerialPort();
        IModbusMaster master;
        private object _lock1 = new object();
        AxisParm AxisZ = default;
        bool isMoving = false;
        bool isPrtMoving = false;
        bool isJogButtonPressing = false;
        #endregion
        #region 属性绑定
        private string fileName;
        public string FileName
        {
            get { return fileName; }
            set { SetProperty(ref fileName, value); }
        }
        private bool weldingCardState;
        public bool WeldingCardState
        {
            get { return weldingCardState; }
            set { SetProperty(ref weldingCardState, value); }
        }
        private bool axisCardState;
        public bool AxisCardState
        {
            get { return axisCardState; }
            set { SetProperty(ref axisCardState, value); }
        }
        private bool isBusy;
        public bool IsBusy
        {
            get { return isBusy; }
            set { SetProperty(ref isBusy, value); }
        }
        private Image mImage;
        public Image MImage
        {
            get { return mImage; }
            set { SetProperty(ref mImage, value); }
        }
        private double speed;
        public double Speed
        {
            get { return speed; }
            set { SetProperty(ref speed, value); }
        }
        private double current;
        public double Current
        {
            get { return current; }
            set { SetProperty(ref current, value); }
        }
        private bool isServoOn;
        public bool IsServoOn
        {
            get { return isServoOn; }
            set { SetProperty(ref isServoOn, value); }
        }
        private double prfPos;
        public double PrfPos
        {
            get { return prfPos; }
            set { SetProperty(ref prfPos, value); }
        }
        private double encPos;
        public double EncPos
        {
            get { return encPos; }
            set { SetProperty(ref encPos, value); }
        }
        private bool IsRemoteSi;
        public bool IsRemoteSW
        {
            get { return IsRemoteSi; }
            set { SetProperty(ref IsRemoteSi, value); }
        }
        private bool isAcitveSW;
        public bool IsAcitveSW
        {
            get { return isAcitveSW; }
            set { SetProperty(ref isAcitveSW, value); }
        }
        private double jogDist;
        public double JogDist
        {
            get { return jogDist; }
            set { SetProperty(ref jogDist, value); }
        }
        private double weldingPos;
        public double WeldingPos
        {
            get { return weldingPos; }
            set { SetProperty(ref weldingPos, value); }
        }
        private double power;
        public double Power
        {
            get { return power; }
            set { SetProperty(ref power, value); }
        }
        private PlotModel plotModel1;
        public PlotModel PlotModel1
        {
            get { return plotModel1; }
            set { SetProperty(ref plotModel1, value); }
        }
        public string Title { get; set; } = "TestDemo";
        public string Version { get; set; } = "1.0";
        #endregion
        #region 方法绑定
        private DelegateCommand redLineCommand;
        public DelegateCommand RedLineCommand =>
            redLineCommand ?? (redLineCommand = new DelegateCommand(ExecuteRedLineCommand));
        private DelegateCommand emissionCommand;
        public DelegateCommand EmissionCommand =>
            emissionCommand ?? (emissionCommand = new DelegateCommand(ExecuteEmissionCommand));
        private DelegateCommand selectFileCommand;
        public DelegateCommand SelectFileCommand =>
            selectFileCommand ?? (selectFileCommand = new DelegateCommand(ExecuteSelectFileCommand));
        private DelegateCommand appLoadedEventCommand;
        public DelegateCommand AppLoadedEventCommand =>
            appLoadedEventCommand ?? (appLoadedEventCommand = new DelegateCommand(ExecuteAppLoadedEventCommand));
        private DelegateCommand appClosedEventCommand;
        public DelegateCommand AppClosedEventCommand =>
            appClosedEventCommand ?? (appClosedEventCommand = new DelegateCommand(ExecuteAppClosedEventCommand));
        private DelegateCommand servoOnCommand;
        public DelegateCommand ServoOnCommand =>
            servoOnCommand ?? (servoOnCommand = new DelegateCommand(ExecuteServoOnCommand));
        private DelegateCommand remoteSWCommand;
        public DelegateCommand RemoteSWCommand =>
            remoteSWCommand ?? (remoteSWCommand = new DelegateCommand(ExecuteRemoteSWCommand));
        private DelegateCommand acitveSWCommand;
        public DelegateCommand AcitveSWCommand =>
            acitveSWCommand ?? (acitveSWCommand = new DelegateCommand(ExecuteAcitveSWCommand));
        private DelegateCommand jogDistValueChangedCommand;
        public DelegateCommand JogDistValueChangedCommand =>
            jogDistValueChangedCommand ?? (jogDistValueChangedCommand = new DelegateCommand(ExecuteJogDistValueChangedCommand));
        private DelegateCommand getWeldingPosCommand;
        public DelegateCommand GetWeldingPosCommand =>
            getWeldingPosCommand ?? (getWeldingPosCommand = new DelegateCommand(ExecuteGetWeldingPosCommand));
        private DelegateCommand goWeldingPosCommand;
        public DelegateCommand GoWeldingPosCommand =>
            goWeldingPosCommand ?? (goWeldingPosCommand = new DelegateCommand(ExecuteGoWeldingPosCommand));
        private DelegateCommand<object> jog_MouseDownCommand;
        public DelegateCommand<object> Jog_MouseDownCommand =>
            jog_MouseDownCommand ?? (jog_MouseDownCommand = new DelegateCommand<object>(ExecuteJog_MouseDownCommand));
        private DelegateCommand jog_MouseUpCommand;
        public DelegateCommand Jog_MouseUpCommand =>
            jog_MouseUpCommand ?? (jog_MouseUpCommand = new DelegateCommand(ExecuteJog_MouseUpCommand));
        private DelegateCommand testButtonCommand;
        public DelegateCommand TestButtonCommand =>
            testButtonCommand ?? (testButtonCommand = new DelegateCommand(ExecuteTestButtonCommand));

        void ExecuteTestButtonCommand()
        {
            int pls = ReadInovance(1);
            Debug.WriteLine(pls);
        }
        void ExecuteJog_MouseUpCommand()
        {
            isJogButtonPressing = false;
            if (!isPrtMoving)
            {
                GTSCard.AxisStop(AxisZ, 0);
                IsBusy = false;
            }
        }
        void ExecuteJog_MouseDownCommand(object obj)
        {
            int index = int.Parse(obj.ToString());
            isJogButtonPressing = true;
            if (!isPrtMoving)
            {
                IsBusy = true;
                isPrtMoving = true;
                source2 = new CancellationTokenSource();
                CancellationToken token = source2.Token;
                var curPos = GTSCard.GetPos(AxisZ);
                double tarPos = 0;
                if (index % 2 == 0)
                {
                    tarPos = curPos + JogDist;
                }
                else
                {
                    tarPos = curPos - JogDist;
                }
                Task.Run(() => GoAction(token, tarPos, 10), token).ContinueWith(arg => {
                  
                    isPrtMoving = false;
                    if (isJogButtonPressing)
                    {
                        
                        int dir = index % 2 == 0 ? 1 : 0;
                        GTSCard.AxisJog(AxisZ, (ushort)dir, 10);
                    }
                    else
                    {
                        IsBusy = false;
                    }
                });
            }

          

        }
        void ExecuteGoWeldingPosCommand()
        {
            if (MessageBox.Show("确定运动到焊接位吗？", "确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == System.Windows.Forms.DialogResult.Yes)
            {
                IsBusy = true;
                isPrtMoving = true;
                source2 = new CancellationTokenSource();
                CancellationToken token = source2.Token;
                Task.Run(() => GoAction(token, WeldingPos, 10), token).ContinueWith(arg => {
                    IsBusy = false;
                    isPrtMoving = false;
                });
            }
        }
        void ExecuteGetWeldingPosCommand()
        {
            if (MessageBox.Show("确定示教焊接位吗？", "确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == System.Windows.Forms.DialogResult.Yes)
            {
                param.WeldingPos = WeldingPos = Math.Round(GTSCard.GetEnc(AxisZ), 3);
                string jsonString = JsonConvert.SerializeObject(param, Formatting.Indented);
                File.WriteAllText(System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "Param.json"), jsonString);
            }
        }
        void ExecuteJogDistValueChangedCommand()
        {
            param.JogDist = JogDist;            
            string jsonString = JsonConvert.SerializeObject(param, Formatting.Indented);
            File.WriteAllText(System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "Param.json"), jsonString);
        }
        void ExecuteAcitveSWCommand()
        {
            if (IsAcitveSW)
            {
                GTSCard.SetDo(AxisZ.CardNo, 1, 1);
            }
            else
            {
                GTSCard.SetDo(AxisZ.CardNo, 1, 0);
            }
        }
        void ExecuteRemoteSWCommand()
        {
            if (IsRemoteSW)
            {
                GTSCard.SetDo(AxisZ.CardNo, 0, 1);
            }
            else
            {
                GTSCard.SetDo(AxisZ.CardNo, 0, 0);
            }
        }
        async void ExecuteServoOnCommand()
        {
            if (IsServoOn)
            {
                GTSCard.ServoOff(AxisZ);
            }
            else
            {
                GTSCard.ServoOn(AxisZ);
                IsBusy = true;
                await Task.Delay(500);
                GTSCard.AxisPosSet(AxisZ, GTSCard.GetEnc(AxisZ));
                IsBusy = false;
            }
        }
        void ExecuteAppClosedEventCommand()
        {
            try
            {
                if (source != null)
                {
                    source.Cancel();
                }
                if (source0 != null)
                {
                    source0.Cancel();
                }
                if (source2 != null)
                {
                    source2.Cancel();
                }
                JczLmc.StopMark();
                ServoModbusClose();
                GTSCard.AxisStop(AxisZ, 1);
                GTSCard.ServoOff(AxisZ);
                GTSCard.SetDo(AxisZ.CardNo, 0, 1);
                GTSCard.SetDo(AxisZ.CardNo, 1, 1);
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }
        }
        void ExecuteAppLoadedEventCommand()
        {
            try
            {
                FileName = param.FileName;
                var r1 = JczLmc.LoadEzdFile(param.FileName);
                MImage = JczLmc.GetCurPreviewImage(800, 600);
                var mes = GetEzdMessage();
                Speed = mes.Item1;
                Current = mes.Item2;

                int pls = ReadInovance(1);
                GTSCard.AxisPosSet(AxisZ, pls * AxisZ.Equiv);
                GTSCard.AxisEncSet(AxisZ, pls * AxisZ.Equiv);

                source0 = new CancellationTokenSource();
                CancellationToken token = source0.Token;
                Task.Run(() => UpdateAxisStatus(token), token);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        void ExecuteSelectFileCommand()
        {
            try
            {
                using var dlg = new OpenFileDialog();
                dlg.Title = "选择";
                dlg.Filter = "选择模板(*.ezd)|*.ezd*";
                if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    FileName =  param.FileName = FileName = dlg.FileName;
                    string jsonString = JsonConvert.SerializeObject(param, Formatting.Indented);
                    File.WriteAllText(System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "Param.json"), jsonString);
                    var r1 = JczLmc.LoadEzdFile(param.FileName);
                    MImage = JczLmc.GetCurPreviewImage(800, 600);
                    var mes = GetEzdMessage();
                    Speed = mes.Item1;
                    Current = mes.Item2;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        void ExecuteEmissionCommand()
        {
            IsBusy = true;
            PlotModel1.Series.Clear();
            PlotModel1.InvalidatePlot(true);
            source3 = new CancellationTokenSource();
            CancellationToken token = source3.Token;
            Task.Run(() => GetPowerLine(token), token);
            Task.Run(() =>
            {
                JczLmc.Mark(false);
            }).ContinueWith(t => { IsBusy = false; source3.Cancel(); });
        }
        void ExecuteRedLineCommand()
        {
            IsBusy = true;
            source = new CancellationTokenSource();
            CancellationToken token = source.Token;
            Task.Run(() => RedLineAction(token), token);
            dialogService.ShowDialog("RedLineWorkDialog",arg => {
                source.Cancel();
                JczLmc.StopMark();
                if (arg.Result == ButtonResult.Cancel)
                {
                    var actIndex = arg.Parameters.GetValue<int>("Act");
                    if (actIndex == 1)
                    {
                        PlotModel1.Series.Clear();
                        PlotModel1.InvalidatePlot(true);
                        source3 = new CancellationTokenSource();
                        CancellationToken token = source3.Token;
                        Task.Run(() => GetPowerLine(token), token);
                        Task.Run(() =>
                        {
                            JczLmc.Mark(false);
                        }).ContinueWith(t => { IsBusy = false; source3.Cancel(); });
                    }
                    else
                    {
                        IsBusy = false;
                    }
                }
                else
                {
                    IsBusy = false;
                }
            });
        }
        #endregion
        #region 构造函数
        public MainWindowViewModel(IContainerProvider containerProvider)
        {
            IsBusy = false;
            IsServoOn = false;
            PlotModel1 = new PlotModel { Title = "功率曲线", TitleColor = OxyColor.FromRgb(32, 32, 32) };
            PlotModel1.PlotAreaBorderColor = OxyColor.FromRgb(32, 32, 32);
            PlotModel1.TextColor = OxyColor.FromRgb(32, 32, 32);
            PlotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, MajorGridlineStyle = LineStyle.Dot, Title = "时间", TicklineColor = OxyColor.FromRgb(32, 32, 32) });
            PlotModel1.Axes.Add(new LinearAxis { Position = AxisPosition.Left, MajorGridlineStyle = LineStyle.Dot, Title = "功率（W）",Maximum = 1000, TicklineColor = OxyColor.FromRgb(32, 32, 32) });
            PlotModel1.InvalidatePlot(true);
            AxisZ.Equiv = 0.001;
            AxisZ.CardNo = 0;
            AxisZ.AxisId = 1;
            AxisZ.Acc = 5;
            dialogService = containerProvider.Resolve<IDialogService>();
            LoadParam();
            JogDist = param.JogDist;
            WeldingPos = param.WeldingPos;
            int nErr = JczLmc.Initialize(System.AppDomain.CurrentDomain.BaseDirectory, false);
            if (nErr != 0)
            {
                MessageBox.Show("打标卡初始化失败-->" + JczLmc.GetErrorText(nErr), "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                //app is already running! Exiting the application  
                //Environment.Exit(-1);
            }
            else
            {
                WeldingCardState = true;
            }
            var axisCardResult = AxisCardInit();
            if (axisCardResult)
            {
                AxisCardState = true;
            }
            else
            {
                AxisCardState = false;
                MessageBox.Show("轴卡初始化失败-->", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                //Environment.Exit(-1);
            }
            var servoModbusState = ServoModbusConnect(param.COM);
            if (!servoModbusState)
            {
                MessageBox.Show("伺服串口初始化失败-->", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                //Environment.Exit(-1);
            }
        }
        #endregion
        #region 功能函数
        private void LoadParam()
        {
            try
            {
                //Json序列化，从文件读取
                string jsonString = File.ReadAllText(System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "Param.json"));
                param = JsonConvert.DeserializeObject<Param>(jsonString);
            }
            catch (Exception ex)
            {
                param = new Param();
                MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        private Tuple<double, double> GetEzdMessage()
        {
            int nMarkLoop = 0;
            double dMarkSpeed = 0;
            double dPowerRatio = 0;
            double dCurrent = 0;
            int nFreq = 0;
            double dQPulseWidth = 0;
            int nStartTC = 0;
            int nLaserOffTC = 0;
            int nEndTC = 0;
            int nPolyTC = 0;
            double dJumpSpeed = 0;
            int nJumpPosTC = 0;
            int nJumpDistTC = 0;
            double dEndComp = 0;
            double dAccDist = 0;
            double dPointTime = 0;
            bool bPulsePointMode = false;
            int nPulseNum = 0;
            double dFlySpeed = 0;
            JczLmc.GetPenParam(1, ref nMarkLoop, ref dMarkSpeed, ref dPowerRatio, ref dCurrent, ref nFreq, ref dQPulseWidth, ref nStartTC,
                ref nLaserOffTC, ref nEndTC, ref nPolyTC, ref dJumpSpeed, ref nJumpPosTC, ref nJumpDistTC, ref dEndComp, ref dAccDist,
                ref dPointTime, ref bPulsePointMode, ref nPulseNum, ref dFlySpeed);
            return new Tuple<double, double>(dMarkSpeed, dCurrent);
        }
        private void RedLineAction(CancellationToken token)
        {
            while (true)
            {
                if (token.IsCancellationRequested)
                {
                    return;
                }
                try
                {
                    JczLmc.RedMarkContour();
                }
                catch { }
                System.Threading.Thread.Sleep(10);
            }
        }
        private bool AxisCardInit()
        {
            try
            {
                var SRtn = gts.mc.GT_Open(0, 0, 1);
                if (SRtn != 0)
                {
                    return false;
                }
                SRtn = gts.mc.GT_Reset(0);
                if (SRtn != 0)
                {
                    return false;
                }
                SRtn = gts.mc.GT_LoadConfig(0, "Top_A8.cfg");
                if (SRtn != 0)
                {
                    return false;
                }
                SRtn = gts.mc.GT_ClrSts(0, 1, 8);
                if (SRtn != 0)
                {
                    return false;
                }
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }
        private bool ServoModbusConnect(string _portName)
        {
            try
            {
                if (serialPort.IsOpen)
                {
                    Debug.WriteLine($"伺服串口{_portName}已打开");
                    return false;
                }
                else
                {
                    serialPort.PortName = _portName;
                    serialPort.BaudRate = 19200;
                    serialPort.DataBits = 8;
                    serialPort.Parity = Parity.Even;
                    serialPort.StopBits = StopBits.One;
                    serialPort.Open();
                    serialPort.DiscardInBuffer();
                    serialPort.DiscardOutBuffer();
                    serialPort.WriteTimeout = 500;
                    serialPort.ReadTimeout = 500;
                    var factory = new ModbusFactory();
                    master = factory.CreateRtuMaster(serialPort);
                    return true;
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
            return false;
        }
        private int ReadInovance(byte station)
        {
            object @lock = this._lock1;
            lock (@lock)
            {
                ushort[] r = master.ReadHoldingRegisters(station, 0x0B07, 2);//H0B-07 绝对位置计数器（32位）H05-30参数写6，清零
                return Convert.ToInt32(r[1].ToString("X4") + r[0].ToString("X4"), 16);
            }
        }
        private void ServoModbusClose()
        {
            try
            {
                master.Dispose();
                serialPort.Close();
                serialPort.Dispose();
            }
            catch { }
        }
        private void UpdateAxisStatus(CancellationToken token)
        {
            while (true)
            {
                if (token.IsCancellationRequested)
                {
                    return;
                }
                try
                {
                    AxisStatus astatus = GTSCard.GetAxisStatus(AxisZ);
                    IsServoOn = astatus.FlagServoOn;
                    isMoving = !astatus.FlagMoveEnd;
                    PrfPos = Math.Round(astatus.PrfPos, 3);
                    EncPos = Math.Round(astatus.EncPos, 3);
                    IsRemoteSW = GTSCard.GetDo(AxisZ.CardNo, 0);
                    IsAcitveSW = GTSCard.GetDo(AxisZ.CardNo, 1);
                    var adcv = GTSCard.GetAdc(1);
                    Power = Math.Round(adcv / 4 * 1000, 0);
                }
                catch { }
                System.Threading.Thread.Sleep(200);
            }
        }
        private void GoAction(CancellationToken token,double Pos,double speed)
        {
            try
            {
                int stepnum = 0;
                while (true)
                {
                    if (token.IsCancellationRequested)
                    {
                        return;
                    }
                    switch (stepnum)
                    {
                        case 0:
                            {
                                GTSCard.AxisPosMove(ref AxisZ, Pos, speed);
                                stepnum = 1;
                            }
                            break;
                        case 1:
                            if (GTSCard.AxisPosMoveCheckDone(AxisZ))
                            {
                                return;
                            }
                            break;
                        default:
                            break;
                    }
                    System.Threading.Thread.Sleep(10);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }
        }
        private void GetPowerLine(CancellationToken token)
        {
            var s1 = new LineSeries { LineStyle = LineStyle.Solid, Color = OxyColors.SpringGreen, TrackerFormatString = "{4:f0}瓦" };
            int i = 0;
            while (true)
            {
                if (token.IsCancellationRequested)
                {
                    PlotModel1.Series.Add(s1);
                    PlotModel1.InvalidatePlot(true);
                    return;
                }
                try
                {
                    var adcv = GTSCard.GetAdc(1);
                    var power1 = Math.Round(adcv / 4 * 1000, 0);
                    s1.Points.Add(new DataPoint(i++, power1));
                }
                catch { }
                System.Threading.Thread.Sleep(1);
            }
        }
        #endregion
    }
}
